-module(utils).
-include_lib("records.hrl").
-compile(export_all).

server() ->
  id(0)
  .

id(Now) ->
  receive
    {From, id} ->
      From!{self(), Now},
      id(Now+1);
    {From, close} ->
      From ! close
  end.

reset_random()->
  {A1,A2,A3}=now(),
  random:seed(A1,A2,A3).

exp_random(Mean) ->
  -Mean*math:log(1-random:uniform()).

get_max(0,Max) ->
  Max;

get_max(N,Max) ->
  receive
    {_, {max, CMax}} ->
      if
        CMax > Max ->
          NewMax = CMax;
        true ->
          NewMax = Max
      end
  end,
  get_max(N-1,NewMax).

run_tdm(Models, Time, MaxTime) ->
  if
    Time rem 1000 =:=0 ->
      io:format("Finish Time:~p~n",[Time]);
    true ->
      ok
  end,
  if
    Time < MaxTime ->
      send_change_tdm(Models, Time),
      run_tdm(Models, Time+1, MaxTime);
    true ->
      finish
  end.

send_change_tdm([], _)->
  ok;

send_change_tdm([H|T], Time)->
  H ! {self(), {time_change, Time}},
  H ! {self(), finish},
  receive
    ok ->
      ok
  end,
  send_change_tdm(T, Time)
  .

sleep(T) ->
  receive
  after T ->
     true
  end.

close_tdm([]) ->
  ok;
close_tdm([H|T]) ->
  H ! {self(), close},
  receive
    _ ->
      ok
  end,
  sleep(100),
  close_tdm(T).

results_tdm(Routers) ->
  results_tdm(Routers, [] ,[]).

results_tdm([], Rec, Loss)->
  {Rec, Loss};

results_tdm([H|T], Rec, Loss)->
  H ! {self(), result},
  receive
    {_, HRec, HLoss} ->
      NewRec = lists:append(Rec, HRec),
      NewLoss = lists:append(Loss, HLoss)
  end,
  results_tdm(T, NewRec, NewLoss).

get_id(Utils) ->
  Utils ! {self(), id},
  receive
    {Utils, Id} ->
      Id
  end.

display_results_tdm(Rec, Loss) ->
  display_total_results_tdm(Rec, Loss).

display_total_results_tdm(Rec, Loss)->
  LossSize = length(Loss),
  RecSize = length(Rec),
  io:format("Total Lost Packet Size:~p~n",[LossSize]),
  io:format("Total Success Packet Size:~p~n",[RecSize]),
  io:format("Total Loss Rate:~p~n",[LossSize/(LossSize+RecSize)]),
  {RecL, RecDelay} = delay_mean_tdm(Rec),
  io:format("Total Rec(~p) Mean Delay time: ~p~n",[RecL, RecDelay]),
  {LossL, LossDelay} = delay_mean_tdm(Loss),
  io:format("Total Loss(~p) Mean Delay time: ~p~n",[LossL, LossDelay]).

delay_mean_tdm(Rec) ->
  delay_mean_tdm(Rec, length(Rec), 0).

delay_mean_tdm([], L, T)->
  if
    L=:=0 ->
      {L, 0.0};
    true ->
      {L, T/L}
  end;

delay_mean_tdm([H|T], L, Time)->
  #packet{timestamps=Timestamps} = H,
  if
    length(Timestamps)=:=0 ->
      NewTime = Time,
      NewL = L - 1;
    true ->
      NewTime = Time+delay_mean_tdm(Timestamps, 0),
      NewL = L
  end,
  delay_mean_tdm(T, NewL, NewTime).

delay_mean_tdm([], Time)->
  Time;

delay_mean_tdm([H|T], Time)->
  #timestamp{atime=ArriveTime, ltime=LeaveTime}=H,
  NewTime = Time+LeaveTime-ArriveTime,
  delay_mean_tdm(T, NewTime)
  .

